﻿using System;
using System.Collections;
using System.Collections.Generic;
using Cms.Domain;
using Cms.Utilities;
using NHibernate;
using NHibernate.Type;

namespace Cms.Data.ORM
{
    public class AuditLogInterceptor : EmptyInterceptor
    {
        private readonly ISet<IAuditable> _deletes = new HashSet<IAuditable>();
        private readonly ISet<IAuditable> _inserts = new HashSet<IAuditable>();
        private readonly ISet<IAuditable> _updates = new HashSet<IAuditable>();
        private ISession _session;
        private int _userID;
        private int _administratorID;
        
        public ISession Session
        {
            get { return _session; }
            set { _session = value; }
        }

        public int AdministratorID
        {
            get { return _administratorID; }
            set { _administratorID = value; }
        }

        public int UserID
        {
            get { return _userID; }
            set { _userID = value; }
        }

        public override bool OnSave(object entity, object id, object[] state, string[] propertyNames, IType[] types)
        {
            if (entity is IAuditable)
            {
                _inserts.Add((IAuditable)entity);
            }
            return base.OnSave(entity, id, state, propertyNames, types);
        }
        
        public override bool OnFlushDirty(object entity, object id, object[] currentState, object[] previousState, string[] propertyNames, IType[] types)
        {
            if (entity is IAuditable)
            {
                _updates.Add((IAuditable)entity);
            }
            return base.OnFlushDirty(entity, id, currentState, previousState, propertyNames, types);
        }
        
        public override void OnDelete(object entity, object id, object[] state, string[] propertyNames, IType[] types)
        {
            if (entity is IAuditable)
            {
                _deletes.Add((IAuditable)entity);
            }
            base.OnDelete(entity, id, state, propertyNames, types);
        }

        public override void AfterTransactionCompletion(ITransaction tx)
        {
            try
            {
                foreach (IAuditable entity in _inserts)
                {
                    AuditLog.LogEvent(LogTypes.Create, entity, _administratorID, _userID, _session);
                }
                foreach (IAuditable entity in _updates)
                {
                    AuditLog.LogEvent(LogTypes.Update, entity, _administratorID, _userID, _session);
                }
                foreach (IAuditable entity in _deletes)
                {
                    AuditLog.LogEvent(LogTypes.Delete, entity, _administratorID, _userID, _session);
                }
            }
            catch (Exception ex)
            {
                Logging.LogError("AuditLogging exception", ex);
            }
            finally
            {
                _inserts.Clear();
                _updates.Clear();
                _deletes.Clear();
            }
        }

        public override void PostFlush(ICollection entities)
        {
        }
    }
}